<?php

namespace App\Logic;

use App\Model\Chat;
use App\Model\Friend;
use App\Model\FriendApply;
use App\Service\PushService;
use App\Utils\Enum\ChatEnum;
use App\Utils\Msg;
use Exception;
use Hyperf\Context\ApplicationContext;
use Hyperf\DbConnection\Db;
use Hyperf\Snowflake\IdGeneratorInterface;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;

class ChatLogic
{
    /**
     * 获取联系人
     * @param $userid
     * @param $input
     * @return array
     */
    public static function getContact($userid, $input): array
    {
        [$pageNum, $pageSize, $offset] = parsePageParams($input, 50);
        $total = Friend::query()->where('userid', $userid)->count();
        if ($total) {
            $res = Friend::with(['user', 'lastChat'])->where('userid', $userid)->offset($offset)->limit($pageSize)->orderBy('last_time', 'desc')->get();
            $records = [];
            foreach ($res as $r) {
                $records[] = [
                    'userId' => $r['user']['id'],
                    'nickname' => $r['user']['nickname'],
                    'avatar' => img_url($r['user']['avatar']),
                    'lastChat' => $r['lastChat']
                ];
            }
        }
        return [
            'total' => $total,
            'pages' => ceil($total / $pageSize),
            'records' => $records ?? [],
        ];
    }

    /**
     * 添加好友
     * @throws Exception
     */
    public static function addFriend($userid, $targetUserId, $message): true
    {
        if (Friend::query()->where(['userid' => $userid, 'friend_userid' => $targetUserId])->exists()) {
            throw new Exception('你们已经是朋友了');
        }
        //是否正好对方有加好友请求
        $waitApply = Friend::query()->where(['userid' => $targetUserId, 'to_userid' => $userid, 'status' => ChatEnum::APPLY_STATUS_WAIT])->first();
        if ($waitApply) {
            return self::opFriendApply($userid, $waitApply['id'], ChatEnum::APPLY_STATUS_AGREE);
        }
        $applyCount = Friend::query()->where(['userid' => $userid, 'to_userid' => $targetUserId])->count();
        if ($applyCount >= 3) {
            throw new Exception('添加好友次数超过限制');
        }
        $lastApply = Friend::query()->where(['userid' => $userid, 'to_userid' => $targetUserId])->orderBy('id', 'desc')->first();
        if ($lastApply && $lastApply['status'] == ChatEnum::APPLY_STATUS_WAIT) {
            throw new Exception('对方处理前，不可重复发送请求');
        }
        $apply = FriendApply::create([
            'userid' => $userid,
            'to_userid' => $targetUserId,
            'message' => $message,
            'status' => ChatEnum::APPLY_STATUS_WAIT,
            'apply_time' => 0,
            'op_time' => 0,
        ]);
        if (!$apply) {
            throw new Exception('申请失败');
        }
        //TODO 通知用户
        return true;
    }

    /**
     * 处理请求
     * @throws Exception
     */
    public static function opFriendApply($userid, $applyId, $op): true
    {
        $apply = FriendApply::query()->where(['id' => $applyId, 'to_userid' => $userid])->first();
        if (!$apply) {
            throw new Exception('申请不存在');
        }
        if ($apply['status'] != ChatEnum::APPLY_STATUS_WAIT) {
            throw new Exception('该申请已经处理过了');
        }
        Db::beginTransaction();
        $ret1 = FriendApply::query()->where('id', $applyId)->update(['status' => $op, 'op_time' => time()]);
        if ($op == ChatEnum::APPLY_STATUS_AGREE) {
            $ret2 = Friend::query()->insert([
                ['userid' => $apply['userid'], 'friend_userid' => $apply['to_userid'], 'last_time' => time(), 'add_time' => time()],
                ['userid' => $apply['to_userid'], 'friend_userid' => $apply['userid'], 'last_time' => time(), 'add_time' => time()],
            ]);
        }

        if (!$ret1 || isset($ret2) && !$ret2) {
            Db::rollBack();
            throw new Exception('操作失败');
        }
        return true;
    }

    /**
     * 是否为朋友
     * @param $userid
     * @param $targetUserId
     * @return bool
     */
    public static function isFriend($userid, $targetUserId): bool
    {
        return Friend::query()->where(['userid' => $userid, 'friend_userid' => $targetUserId])->exists();
    }

    /**
     * 发送消息
     * @param $userid
     * @param $toUserId
     * @param $msgType
     * @param $msgBody
     * @return true
     * @throws ContainerExceptionInterface
     * @throws NotFoundExceptionInterface
     * @throws Exception
     */
    public static function sendMsg($userid, $toUserId, $msgType, $msgBody): true
    {
        if (!self::isFriend($userid, $toUserId)) {
            throw new Exception('不能给非朋友发消息');
        }
        try {
            $container = ApplicationContext::getContainer();
            $generator = $container->get(IdGeneratorInterface::class);
        } catch (Exception $e) {
            throw new Exception('系统繁忙');
        }

        $msg = Chat::create([
            'msg_id' => $generator->generate(),
            'from_userid' => $userid,
            'to_userid' => $toUserId,
            'msg_type' => $msgType,
            'msg_content' => is_array($msgBody) ? new_json_encode($msgBody) : $msgBody,
            'is_read' => ChatEnum::MSG_NOT_READ,
            'send_time' => time(),
            'read_time' => 0,
        ]);
        if (!$msg) {
            throw new Exception('发送失败');
        }
        PushService::send($toUserId, Msg::Create('USER_NEW_CHAT_MSG', ['msg_id' => $msg['msg_id'], 'userid' => $userid]));
        //TODO 消息推送
        return true;
    }

    /**
     * 获取消息列表
     * @param $userid
     * @param $targetUserId
     * @param $lastMsgId
     * @param $msgNum
     * @param $autoRead
     * @return array
     */
    public static function getMessageList($userid, $targetUserId, $lastMsgId, $msgNum, $autoRead = false): array
    {
        $chatKey = self::getChatKey($userid, $targetUserId);
        $_msgId = 0;
        if ($lastMsgId) {
            $msg = Chat::query()->where('msg_id', $lastMsgId)->first();
            if (!$msg || $msg['chat_key'] != $chatKey) {
                return [];
            }
            $_msgId = $msg['id'];
        }
        $query = Chat::query()->where('chat_key', $chatKey);
        if ($_msgId) {
            $query->where('id', '<', $_msgId);
        }
        $res = $query->orderBy('id')->limit($msgNum)->select()->get();
        if ($autoRead && $res) {
            $ids = array_column($res->toArray(), 'id');
            Chat::query()->where('id', 'in', $ids)->update(['read_time' => time(), 'is_read' => ChatEnum::MSG_IS_READ]);
        }
        $records = [];
        foreach ($res as $r) {
            $records[] = [
                'msgId' => $r['msg_id'],
                'fromUserId' => $r['from_userid'],
                'toUserId' => $r['to_userid'],
                'msgType' => $r['msg_type'],
                'msgContent' => $r['msg_content'],
                'isRead' => $autoRead ? 1 : 0,
                'sendTime' => $r['send_time'],
                'readTime' => $autoRead ? time() : $r['read_time'],
            ];
        }
        unset($res);
        return $records;
    }

    /**
     * 获取对话KEY
     * @param $userid
     * @param $targetUserId
     * @return string
     */
    public static function getChatKey($userid, $targetUserId): string
    {
        $userIds = [$userid, $targetUserId];
        sort($userIds);
        return implode('-', $userIds);
    }


}